package com.ruoyi.web.controller.system;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.util.*;

import com.alibaba.fastjson.JSON;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.loginrisk.controller.LoginRiskController;
import com.ruoyi.loginrisk.service.ISysLoginRiskService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysMenu;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginBody;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.framework.web.service.SysLoginService;
import com.ruoyi.framework.web.service.SysPermissionService;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.system.service.ISysMenuService;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletResponse;

/**
 * 登录验证
 * 
 * @author ruoyi
 */
@RestController
public class SysLoginController
{
    private static final Logger log = LoggerFactory.getLogger(SysLoginController.class);
    @Autowired
    private SysLoginService loginService;

    @Autowired
    private ISysMenuService menuService;

    @Autowired
    private SysPermissionService permissionService;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private ISysLoginRiskService loginRiskService;

    /**
     * 登录方法
     * 
     * @param loginBody 登录信息
     * @return 结果
     */
    @PostMapping("/login")
    public void login(@RequestBody LoginBody loginBody,
                      @RequestParam(required = false) String redirect,
                      HttpServletResponse response) throws IOException {
        AjaxResult ajax = AjaxResult.success();
        // 生成令牌
        String token = loginService.login(
                loginBody.getUsername(),
                loginBody.getPassword(),
                loginBody.getCode(),
                loginBody.getUuid());


        //调用风险判断模块
        String url = "http://localhost:9000/loginrisk/login";
        Map<String, String> requestBody = new HashMap<>();
        requestBody.put("userId", String.valueOf(loginService.getUserId()));
        requestBody.put("username", loginBody.getUsername());
        ResponseEntity<Map> responses = restTemplate.postForEntity(url, requestBody, Map.class);
        Map<String, Object> responseBody = responses.getBody();
        System.out.println("=================>风险判断<=================");
        System.out.println("result=========================>" + responseBody);

        ajax.put(Constants.TOKEN, token);

        if (StringUtils.isNotEmpty(redirect)) {
            // 强制HTTPS校验
            if (!redirect.startsWith("https://")&& !redirect.startsWith("http://localhost")) {
                response.sendError(HttpStatus.FORBIDDEN, "Require HTTPS");
                return;
            }

            // 强化域名校验
            if (!isValidRedirect(redirect)) {
                response.sendError(HttpStatus.FORBIDDEN, "Invalid redirect domain");
                return;
            }

            // 规范化 redirect 参数
            String normalizedRedirect = normalizeRedirect(redirect);
            log.info("Normalized redirect URL: {}", normalizedRedirect);

            // 通过302跳转控制流程
            String callbackUrl = "/sso/callback?redirect=" + URLEncoder.encode(redirect, "UTF-8")
                    + "&token=" + URLEncoder.encode(token, "UTF-8");
            response.sendRedirect(callbackUrl);
        } else {
            // 普通登录返回JSON
            response.setContentType("application/json");
            response.getWriter().write(JSON.toJSONString(ajax));
        }

    }

    /**
     * 获取用户信息
     * 
     * @return 用户信息
     */
    @GetMapping("getInfo")
    public AjaxResult getInfo()
    {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        SysUser user = loginUser.getUser();
        // 角色集合
        Set<String> roles = permissionService.getRolePermission(user);
        // 权限集合
        Set<String> permissions = permissionService.getMenuPermission(user);
        if (!loginUser.getPermissions().equals(permissions))
        {
            loginUser.setPermissions(permissions);
            tokenService.refreshToken(loginUser);
        }
        AjaxResult ajax = AjaxResult.success();
        ajax.put("user", user);
        ajax.put("roles", roles);
        ajax.put("permissions", permissions);
        return ajax;
    }

    /**
     * 获取路由信息
     * 
     * @return 路由信息
     */
    @GetMapping("getRouters")
    public AjaxResult getRouters()
    {
        Long userId = SecurityUtils.getUserId();
        List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId);
        return AjaxResult.success(menuService.buildMenus(menus));
    }

    private boolean isValidRedirect(String redirect) {
        // 从配置或数据库获取允许的域名白名单
        List<String> allowedDomains = Arrays.asList(
                "192.168.153.154",
                "localhost",
                "www.baidu.com"

        );

        try {
            URI uri = new URI(redirect);
            String host = uri.getHost();

            // 检查协议和域名
            return "http".equals(uri.getScheme()) || "https".equals(uri.getScheme())
                    && host != null
                    && allowedDomains.stream().anyMatch(domain -> host.equals(domain) || host.endsWith("." + domain));
        } catch (Exception e) {
            return false;
        }
    }

    private String normalizeRedirect(String redirect) {
        try {
            URI uri = new URI(redirect);
            // 确保使用绝对路径
            String normalized = uri.normalize().toString();
            // 移除末尾多余的斜杠
            if (normalized.endsWith("/")) {
                normalized = normalized.substring(0, normalized.length() - 1);
            }
            return normalized;
        } catch (URISyntaxException e) {
            log.error("Failed to normalize redirect URL: {}", redirect, e);
            return redirect;
        }
    }

    @GetMapping("/sso/callback")
    public void ssoCallback(HttpServletResponse response,
                            @RequestParam String token,
                            @RequestParam String redirect) throws IOException {

        // 验证redirect是否为注册的合法域名
        if (!isValidRedirect(redirect)) {
            response.sendError(HttpStatus.FORBIDDEN, "Invalid redirect url");
            return;
        }

//        // 验证token有效性
//        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
//        if (loginUser == null || !loginUser.getToken().equals(token)) {
//            response.sendError(HttpStatus.UNAUTHORIZED, "Invalid token");
//            return;
//        }

        // --- 正确逻辑的开始 ---
        // 通过使用URL查询参数中的token来进行有效性验证
        LoginUser loginUser = tokenService.getLoginUserFromToken(token);
        if (loginUser == null) {
            // 从 login() 过来的原始token无效或已从Redis中过期
            response.sendError(HttpStatus.UNAUTHORIZED, "Invalid token");
            return;
        }
        // --- 正确逻辑的结束 ---

        // 规范化 redirect 参数
        String normalizedRedirect = normalizeRedirect(redirect);
        log.info("Final redirect URL: {}", normalizedRedirect);
        log.info("Token for redirect: {}", token);

        // 跳转回第三方系统（携带state防止CSRF）
        response.sendRedirect(normalizedRedirect + "?token=" + URLEncoder.encode(token, "UTF-8"));
        log.info("Successfully redirected to: {}", normalizedRedirect + "?token=" + URLEncoder.encode(token, "UTF-8"));
    }

    @GetMapping("/sso/authInfo")
    public ResponseEntity<Map<String, Object>> getAuthInfo(@RequestParam String token) {
        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
        if (loginUser == null || !loginUser.getToken().equals(token)) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
        }

        Map<String, Object> authInfo = new HashMap<>();
        authInfo.put("username", loginUser.getUsername());
        authInfo.put("roles", permissionService.getRolePermission(loginUser.getUser()));
        authInfo.put("permissions", permissionService.getMenuPermission(loginUser.getUser()));
        return ResponseEntity.ok(authInfo);
    }
}
